﻿'***********************************************************************
'Magic Chimney Imp (MCI)
'Copyright (C) 2011  David Frendin (david.frendin@gmail.com)
'
'This program is free software: you can redistribute it and/or modify
'it under the terms of the GNU General Public License as published by
'the Free Software Foundation, either version 3 of the License, or
'(at your option) any later version.
'
'This program is distributed in the hope that it will be useful,
'but WITHOUT ANY WARRANTY; without even the implied warranty of
'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'GNU General Public License for more details.
'
'You should have received a copy of the GNU General Public License
'along with this program.  If not, see <http://www.gnu.org/licenses/>.
'***********************************************************************
Imports System.Net
Imports System.IO
Imports System.Text

Public Class frmOracleImporter

    Protected OutputPath As String

#Region " Thread safe control delegates "
    Private Sub SetImportButtonEnabledStatus(ByVal Value As Boolean)
        If KryptonButtonImport.InvokeRequired Then
            KryptonButtonImport.Invoke(New OracleSetImporter.SetImportButtonEnabledStatusDelegate(AddressOf SetImportButtonEnabledStatus), Value)
        Else
            KryptonButtonImport.Enabled = Value
        End If
    End Sub

    Private Sub SetProgressBarStatus(ByVal Value As Integer, ByVal Max As Integer, ByVal Min As Integer)
        If ProgressBar1.InvokeRequired Then
            ProgressBar1.Invoke(New OracleSetImporter.SetProgressBarStatusDelegate(AddressOf SetProgressBarStatus), Value, Max, Min)
        Else
            ProgressBar1.Value = Value
            If Not Max = Nothing Then
                ProgressBar1.Maximum = Max
            End If
            If Not Min = Nothing Then
                ProgressBar1.Minimum = Min
            End If
            My.Application.DoEvents()
        End If
    End Sub

    Private Sub SetInformationBox(ByVal Value As String)
        If KryptonListBox1.InvokeRequired Then
            KryptonListBox1.Invoke(New OracleSetImporter.SetInformationBoxDelegate(AddressOf SetInformationBox), Value)
        Else
            KryptonListBox1.Items.Add(Value)
            KryptonListBox1.SelectedIndex = KryptonListBox1.Items.Count - 1
        End If
    End Sub

    Private Sub SetToolstripText(ByVal Value As String)
        If KryptonListBox1.InvokeRequired Then
            KryptonListBox1.Invoke(New OracleSetImporter.SetToolstripTextDelegate(AddressOf SetToolstripText), Value)
        Else
            ToolStripStatusLabelGeneralStatus.Text = Value
        End If
    End Sub

#End Region

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim CheckAll As Boolean = False
        OutputPath = Application.StartupPath & "\cardpool\"
        For i As Integer = 0 To Environment.GetCommandLineArgs.Count - 1
            'If Environment.GetCommandLineArgs(i) = "-output" Then
            '    OutputPath = Environment.GetCommandLineArgs(i + 1)
            'End If
            'If Environment.GetCommandLineArgs(i) = "-checkall" Then
            CheckAll = True
            'End If
        Next

        Dim sets As ArrayList = GetSets()
        For Each aset As String In sets
            KryptonCheckedListBoxSets.Items.Add(aset)

            KryptonCheckedListBoxSets.SetItemChecked(KryptonCheckedListBoxSets.Items.Count - 1, CheckAll)
        Next
    End Sub

    Protected Function GetSets() As ArrayList
        ToolStripStatusLabelGeneralStatus.Text = "Loading list of sets..."
        Dim result As New ArrayList
        If File.Exists("setlist.xml") Then
            Dim span As TimeSpan = DateTime.Now.Subtract(File.GetLastWriteTime("setlist.xml"))
            If span.Hours > 2 Then
                Return GetSetListFromOracle()
            End If
            Dim xmldoc As New Xml.XmlDocument
            xmldoc.Load("setlist.xml")
            Dim nodes As Xml.XmlNodeList = xmldoc.SelectNodes("/setlist/set")
            For Each node As Xml.XmlNode In nodes
                result.Add(node.InnerText)
            Next
            ToolStripStatusLabelGeneralStatus.Text = "Loading sets from local cache, " & span.Hours.ToString & " hours old"
            Return result
        Else
            Return GetSetListFromOracle()
        End If
    End Function

    Protected Function GetSetListFromOracle() As ArrayList
        Dim result As New ArrayList
        Dim page As String = OracleSetImporter.GetPage("http://gatherer.wizards.com/Pages/Default.aspx")
        Dim startpos As Integer = InStr(page, "MainContent_Content_SearchControls_setAddText""")
        page = Mid(page, startpos + Len("MainContent_Content_SearchControls_setAddText"">"))
        Dim endpos As Integer = InStr(page, "</select>")
        page = Mid(page, 1, endpos - 1)
        page = "<root>" & page & "</root>"

        Dim xmldoc As New Xml.XmlDocument
        xmldoc.LoadXml(page)

        Dim nodes As Xml.XmlNodeList = xmldoc.SelectNodes("/root/option")
        Dim sb As New StringBuilder
        sb.AppendLine("<setlist>")
        For Each node As Xml.XmlNode In nodes
            If Not node.InnerText = String.Empty Then
                result.Add(node.InnerText)
                sb.AppendLine("<set>" & node.InnerText & "</set>")
            End If
        Next
        sb.AppendLine("</setlist>")
        Using sw As New IO.StreamWriter("setlist.xml")
            sw.Write(sb.ToString)
        End Using

        ToolStripStatusLabelGeneralStatus.Text = "Downloaded most current set infomration from oracle"
        Return result
    End Function





    Protected Sub Import()
        Dim IgnoredSets As Integer = 0
        SetImportButtonEnabledStatus(False)
        For Each item In KryptonCheckedListBoxSets.CheckedItems
            If File.Exists(OutputPath & SafeFileName(item) & ".xml") Then
                Dim span As TimeSpan = DateTime.Now.Subtract(File.GetLastWriteTime(OutputPath & SafeFileName(item) & ".xml"))
                If span.Hours < 8 Then
                    IgnoredSets = IgnoredSets + 1
                End If
            End If
        Next

        SetProgressBarStatus(1, KryptonCheckedListBoxSets.CheckedItems.Count - IgnoredSets + 1, 1)
        SetToolstripText("Downloading card sets... Please have patience...")
        My.Application.DoEvents()

        Dim stpWatchInfo As New System.Diagnostics.Stopwatch
        stpWatchInfo.Start()

        Dim al As New Queue
        Dim dq As New Queue


        For Each item In KryptonCheckedListBoxSets.CheckedItems
            Dim IsCurrent As Boolean = False
            If File.Exists(OutputPath & SafeFileName(item) & ".xml") Then
                Dim span As TimeSpan = DateTime.Now.Subtract(File.GetLastWriteTime(OutputPath & SafeFileName(item) & ".xml"))
                If span.Hours < 8 Then
                    IsCurrent = True
                End If
            End If

            If Not IsCurrent Then
                Dim exportParams As New OracleSetImporter.ExportSetStruct
                exportParams.SetName = item
                exportParams.FileName = Me.OutputPath & SafeFileName(item) & ".xml"

                Dim pts As New Threading.ParameterizedThreadStart(AddressOf OracleSetImporter.SaveSet)
                Dim t As New Threading.Thread(pts)
                Dim tqs As New OracleSetImporter.ThreadQueueStruct
                tqs.ExportSet = exportParams

                tqs.Thread = t
                al.Enqueue(tqs)
            Else
                SetInformationBox("Ignored " & item & ", existing local copy is current.")
            End If
        Next


        If al.Count > 0 Then
            Dim tqs2 As OracleSetImporter.ThreadQueueStruct = CType(al.Dequeue, OracleSetImporter.ThreadQueueStruct)
            tqs2.Thread.Start(tqs2.ExportSet)
            SetInformationBox("Importing " & tqs2.ExportSet.SetName & "...")
            dq.Enqueue(tqs2)
            Threading.Thread.Sleep(50)
        End If

        If al.Count > 0 Then
            Dim tqs4 As OracleSetImporter.ThreadQueueStruct = CType(al.Dequeue, OracleSetImporter.ThreadQueueStruct)
            tqs4.Thread.Start(tqs4.ExportSet)
            SetInformationBox("Importing " & tqs4.ExportSet.SetName & "...")
            dq.Enqueue(tqs4)
            Threading.Thread.Sleep(50)
        End If

        If al.Count > 0 Then
            Dim tqs4 As OracleSetImporter.ThreadQueueStruct = CType(al.Dequeue, OracleSetImporter.ThreadQueueStruct)
            tqs4.Thread.Start(tqs4.ExportSet)
            SetInformationBox("Importing " & tqs4.ExportSet.SetName & "...")
            dq.Enqueue(tqs4)
            Threading.Thread.Sleep(50)
        End If

        While dq.Count > 0
            Dim tqs As OracleSetImporter.ThreadQueueStruct = CType(dq.Dequeue, OracleSetImporter.ThreadQueueStruct)
            tqs.Thread.Join()
            If al.Count > 0 Then
                Dim tqs3 As OracleSetImporter.ThreadQueueStruct = CType(al.Dequeue, OracleSetImporter.ThreadQueueStruct)
                tqs3.Thread.Start(tqs3.ExportSet)
                SetInformationBox("Importing " & tqs3.ExportSet.SetName & "...")
                dq.Enqueue(tqs3)
            End If
            SetProgressBarStatus(ProgressBar1.Value + 1, Nothing, Nothing)
            SetInformationBox("Finnished importing " & tqs.ExportSet.SetName)
        End While

        SetInformationBox("XML import complete, compiling master database...")
        Dim all As New StringBuilder
        all.AppendLine("<root>")
        For Each xmlFile As FileInfo In New DirectoryInfo(Me.OutputPath).GetFiles("*.xml")
            If Not xmlFile.Name = "setlist.xml" AndAlso Not xmlFile.Name = "master.xml" Then
                all.Append(xmlFile.OpenText.ReadToEnd)
            End If
        Next
        all.AppendLine("</root>")
        Using MasterXML As New IO.StreamWriter(Me.OutputPath & "\master.xml", False)
            MasterXML.Write(all.ToString)
        End Using
        SetInformationBox("Master database complete, oracle import completed!")

        Beep()

        SetToolstripText("Completed import of " & (ProgressBar1.Value - 1) & " set(s) in " & Math.Round(stpWatchInfo.Elapsed.TotalMinutes, 1).ToString & " minutes")
        SetImportButtonEnabledStatus(True)
    End Sub

    Private Sub KryptonButtonImport_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles KryptonButtonImport.Click
        KryptonListBox1.Items.Clear()
        Threading.ThreadPool.QueueUserWorkItem(New Threading.WaitCallback(AddressOf Import))
    End Sub

    Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExitToolStripMenuItem.Click
        Application.Exit()
    End Sub

    Protected Shared Function SafeFileName(ByVal Value As String) As String
        Value = Replace(Value, ":", "")
        Value = Replace(Value, """", "")
        Value = Replace(Value, ".", "")
        Return Value
    End Function

    Private Sub CheckAllToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckAllToolStripMenuItem.Click
        For i As Integer = 0 To KryptonCheckedListBoxSets.Items.Count - 1
            KryptonCheckedListBoxSets.SetItemChecked(i, True)
        Next
    End Sub

    Private Sub UncheckAllToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UncheckAllToolStripMenuItem.Click
        For i As Integer = 0 To KryptonCheckedListBoxSets.Items.Count - 1
            KryptonCheckedListBoxSets.SetItemChecked(i, False)
        Next
    End Sub

    Private Sub AboutToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AboutToolStripMenuItem.Click
        Dim dlgAbout As New frmAbout
        dlgAbout.ShowDialog(Me)
    End Sub

    Private Sub OpenFileLocationToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OpenFileLocationToolStripMenuItem.Click
        Process.Start("explorer.exe", OutputPath)
    End Sub
End Class
